﻿#ifndef TL_VECTOR_H
#define TL_VECTOR_H

#include "Utility.h"


namespace TL {
    template<class T> class Vector {
    public:
        Vector()
        {
            set_null();
        }
        Vector(int newSize, T defaultValue)
        {
            set_null();
            
            if(newSize > 0) {
                m_Ptr = new T [newSize];

                for(int i = 0; i < newSize; i++)
                    m_Ptr[i] = defaultValue;

                m_Size = newSize;
            }
        }
        Vector(const Vector<T> &vector)
        {
            set_null();
            
            if(vector.m_Size > 0) {
                m_Ptr = new T [vector.m_Size];

                for(int i = 0; i < vector.m_Size; i++)
                    m_Ptr[i] = vector.m_Ptr[i];

                m_Size = vector.m_Size;
            }
        }
        ~Vector()
        {
            if(m_Size > 0)
                delete [] m_Ptr;
        }
        
    public:
        const T &at(int index)
        {
            if(index < 0 || index > m_Size-1)
                return m_Undefined;

            return m_Ptr[index];
        }
        void clear()
        {
            if(m_Size > 0) {
                delete [] m_Ptr;
                
                set_null();
            }
        }
        void insert(int index, T newValue)
        {
            if(index < 0 || index > m_Size)
                return;

            if(m_Size > 0) {
                T *newVector = new T [++m_Size];

                for(int i = 0; i < index; i++)
                    newVector[i] = m_Ptr[i];

                newVector[index] = newValue;

                for(int i = index+1; i < m_Size; i++) // m_Size уже увеличен на 1
                    newVector[i] = m_Ptr[i-1];

                delete [] m_Ptr;
                m_Ptr = newVector;
            } else {
                m_Ptr = new T [++m_Size];
                m_Ptr[0] = newValue;
            }
        }
        void remove(int index)
        {
            if(index < 0 || index > m_Size-1)
                return;

            if(m_Size > 1) {
                T *newVector = new T [m_Size-1];

                for(int i = 0; i < index; i++)
                    newVector[i] = m_Ptr[i];

                for(int i = index+1; i < m_Size; i++)
                    newVector[i-1] = m_Ptr[i];

                delete [] m_Ptr;
                m_Ptr = newVector;
            } else {
                delete [] m_Ptr;
                m_Ptr = 0;
            }

            m_Size--;
        }
        void reverse()
        {
            for(int i = 0; i < m_Size/2; i++) {
                TL::my_swap(&m_Ptr[i], &m_Ptr[m_Size-i-1]);
            }
        }
        const int &size()
        {
            return m_Size;
        }
        
    public:
#ifdef _IOSTREAM_
        friend std::ostream &operator<<(std::ostream &stream, const Vector<T> &vector)
        {
            for(int i = 0; i < vector.m_Size; i++) {
                stream << (i ? "" : "(") << vector.m_Ptr[i] << (i == vector.m_Size-1 ? ")" : ", ");
            }

            return stream;
        }
#endif
        
    public:
        Vector<T> &operator<<(T newValue) // добавляет новый элемент в конец
        {
            if(m_Size > 0) {
                T *newVector = new T [m_Size+1];

                for(int i = 0; i < m_Size; i++)
                    newVector[i] = m_Ptr[i];

                newVector[m_Size++] = newValue;

                delete [] m_Ptr;
                m_Ptr = newVector;
            } else {
                m_Ptr = new T [++m_Size];
                m_Ptr[0] = newValue;
            }

            return *this;
        }
        Vector<T> &operator=(const Vector<T> &vector)
        {
            if(m_Size < 1 && vector.m_Size > 0) {
                m_Ptr = new T [vector.m_Size];

                for(int i = 0; i < vector.m_Size; i++)
                    m_Ptr[i] = vector.m_Ptr[i];
            } else if(m_Size > 0 && vector.m_Size < 1) {
                delete [] m_Ptr;
                m_Ptr = 0;
            } else if(m_Size > 0 && vector.m_Size > 0) {
                if(m_Size != vector.m_Size) {
                    delete [] m_Ptr;
                    m_Ptr = new T [vector.m_Size];
                }

                for(int i = 0; i < vector.m_Size; i++)
                    m_Ptr[i] = vector.m_Ptr[i];
            }
            
            m_Size = vector.m_Size;

            return *this;
        }
        T &operator[](int index)
        {
            return m_Ptr[index];
        }
    
    private:
        T *m_Ptr;
        T m_Undefined;
        int m_Size;

    private:
        void set_null()
        {
            m_Ptr = 0;
            m_Undefined = T();

            m_Size = 0;
        }
    };
}

#endif